package com.ld.security.server.admin.modules.ge.service.impl;

import com.baomidou.dynamic.datasource.DynamicDataSourceCreator;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.ld.security.common.core.util.AesCrypt;
import com.ld.security.common.core.util.JsonUtil;
import com.ld.security.common.core.util.MapUtil;
import com.ld.security.common.core.util.StringUtil;
import com.ld.security.common.mybatis.base.mapping.SqlMapping;
import com.ld.security.common.mybatis.base.service.ISuperServiceImpl;
import com.ld.security.common.mybatis.base.vo.SchemaVo;
import com.ld.security.common.mybatis.constant.SqlCondition;
import com.ld.security.common.mybatis.util.DataSourceUtil;
import com.ld.security.common.mybatis.wrapper.SimpQueryWrapper;
import com.ld.security.server.admin.modules.ge.entity.GeColumnEntity;
import com.ld.security.server.admin.modules.ge.entity.GeDataSourceEntity;
import com.ld.security.server.admin.modules.ge.entity.GeTableEntity;
import com.ld.security.server.admin.modules.ge.po.TableInitPo;
import com.ld.security.server.admin.modules.ge.po.TableSaveDetailsPo;
import com.ld.security.server.admin.modules.ge.service.IGeDataSourceService;
import com.ld.security.server.admin.modules.ge.service.IGeTableService;
import com.ld.security.server.admin.modules.ge.util.ProjectUtil;
import com.ld.security.server.admin.modules.ge.vo.GeColumnVo;
import com.ld.security.server.admin.modules.ge.vo.GeTableVo;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 动态数据源使用id
 * 静态使用code
 */
@Service

@Slf4j
public class GeDataSourceServiceImpl extends ISuperServiceImpl<GeDataSourceEntity>
implements
        IGeDataSourceService {

    @Autowired
    IGeTableService iGeTableService;

    String salt = this.getClass().getSimpleName();

    @Autowired
    SqlMapping sqlMapping;

        @Autowired
        DynamicDataSourceCreator dynamicDataSourceCreator;

    @Override
    public List<GeTableVo> getAllTable(String dataSource) {
        SchemaVo schemaVo =  sqlMapping.getNowSchemaName(dataSource);
        String tableSchema= schemaVo.getSchemaName();

        GeTableVo geTableVo =  new GeTableVo();
        geTableVo.setTableSchema(tableSchema);

        SimpQueryWrapper ew =   new SimpQueryWrapper(geTableVo);
        ew.setDataSource(dataSource);
        List<GeTableVo> geTableVos = JsonUtil.clone(sqlMapping.all(ew),List.class,geTableVo.getClass());
        return geTableVos;
    }

    @Override
    public List<GeColumnVo> getAllColumn(String dataSource, List<String> tables) {
        SchemaVo schemaVo =  sqlMapping.getNowSchemaName(dataSource);
        String tableSchema= schemaVo.getSchemaName();



        GeColumnVo geColumnVo =   new GeColumnVo();
        geColumnVo.setTableSchema(tableSchema);

        SimpQueryWrapper ew =   new SimpQueryWrapper(geColumnVo);
        ew.setDataSource(dataSource);
        ew.where("table_name",SqlCondition.in,tables);
        List<GeColumnVo> geColumnVos = JsonUtil.clone(sqlMapping.all(ew),List.class,geColumnVo.getClass());

        return geColumnVos;
    }

    @Override
        public int initDataSource() {
                List<GeDataSourceEntity> es = this.all();
                for (GeDataSourceEntity e :es) {
                        saveAfter(e);
                }
                return es.size();
        }

    @Override
    public int removeByIds(Collection<String> ids) {
        int total = super.removeByIds(ids);
    for (String id : ids) {

        DataSourceUtil.removeDataSource(id);
    }
        return total;
        }

        @SneakyThrows
        private void saveAfter(GeDataSourceEntity e){


        try{
            String newPassword =
                    AesCrypt.decrypt(e.getPassword());


            String driverClassName =e.getDataSourceType().getDriverClassName();
            String type =e.getDataSourceType().getType();

            Class clazz = Class.forName(type);
            DataSourceProperty dataSourceProperty = new DataSourceProperty();
            dataSourceProperty.setDriverClassName(driverClassName);
            dataSourceProperty.setUrl(e.getUrl());
            dataSourceProperty.setUsername(e.getUsername());
            dataSourceProperty.setPassword(newPassword);
            dataSourceProperty.setType(clazz);
            //5秒超时
            dataSourceProperty.getDruid().setMaxActive(5000);

            DataSource dataSource =  dynamicDataSourceCreator.createDruidDataSource(dataSourceProperty);

            //重复数据源会被覆盖
            DataSourceUtil.addDataSource(e.getId(),dataSource);
        }catch (Exception ex){
            ex.printStackTrace();
        }





        }




    @Override
        public int save(GeDataSourceEntity entity) {

        boolean enCode = false;

            if(StringUtil.isNotNull(entity.getId())){
                GeDataSourceEntity e =   this.getById(entity.getId());
                if(e.getPassword().equals(entity.getPassword())){

                }else{
                    enCode=true;
                }
            }else {
                enCode=true;
            }


            if(enCode){
                String newPassword =  AesCrypt.encrypt(entity.getPassword());
                entity.setPassword(newPassword);
            }

            int total = super.save(entity);
            this.saveAfter(entity);

            return total;
        }

        @PostConstruct
        public void run(){

                this.initDataSource();
        }


    @Override
    public int initTable(TableInitPo po) {

        List<GeTableVo> geTableVos = po.getTables();
        List<GeColumnVo> geColumnVos = this.getAllColumn(po.getDataSourceId(),po.mapTableNames());


       Map<String,List<GeColumnVo>> columnMap = MapUtil.group(geColumnVos,"tableName");


        for (GeTableVo tableVo : geTableVos) {
            String tableName =  tableVo.getTableName();
            List<GeColumnVo> columnVos =  columnMap.get(tableName);

            TableSaveDetailsPo p =  new TableSaveDetailsPo();

            GeTableEntity geTableEntity = JsonUtil.clone(tableVo,GeTableEntity.class);
            geTableEntity.setProjectId(ProjectUtil.getDefProectId());
            geTableEntity.setLabel(tableVo.getTableComment());

            geTableEntity.setDataSourceId(po.getDataSourceId());

            List<GeColumnEntity> geColumnEntities =  columnVos.stream().map((v -> {

                GeColumnEntity geColumnEntity =   JsonUtil.clone(v,GeColumnEntity.class);
                geColumnEntity.setLabel(v.getColumnComment());
                return geColumnEntity;
            })).collect(Collectors.toList());


            p.setTable(geTableEntity);
            p.setColumns(geColumnEntities);
            iGeTableService.tableSaveDetailsPo(p);
        }

            return geTableVos.size();
    }
}
